﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Lyon.MemoryShares
{
    /// <summary>
    /// 跨进程等待锁
    /// </summary>
    public class NamedWaitLock : IDisposable
    {
        string _Name;
        Semaphore value;
        bool _IsDisposed;
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="name"></param>
        public NamedWaitLock(string name)
        {
            this._Name = name;
        }
        /// <summary>
        /// 释放对象
        /// </summary>
        public void Dispose()
        {
            _IsDisposed = true;
            if (value != null)
            {
                value.Close();
                value = null;
            }
        }
        /// <summary>
        /// 等待锁一次
        /// </summary>
        public void WaitLock()
        {
            FindOrCreate(this);
            WaitOne(this.value);
        }
        /// <summary>
        /// 等待开一次
        /// </summary>
        public void WaitUnlock()
        {
            FindOrCreate(this);
            Release(this.value);
        }
        private Semaphore FindOrCreate(NamedWaitLock lockName)
        {
            if (lockName.value == null)
            {
                try
                {
                    lockName.value = Semaphore.OpenExisting(lockName._Name);
                }
                catch
                {
                    lockName.value = new Semaphore(1, 1, lockName._Name);
                }
            }
            return lockName.value;

        }
        private void Release(Semaphore value)
        {
            bool releaseEnd = false;
            while (!releaseEnd)
            {
                CheckDisposed();
                try
                {
                    value.Release();
                    releaseEnd = true;
                }
                catch
                {
                    Thread.Sleep(10);
                }
            }
        }
        private void WaitOne(Semaphore value)
        {
            bool waitOneEnd = false;
            while (!waitOneEnd)
            {
                CheckDisposed();
                try
                {
                    waitOneEnd = value.WaitOne(10);
                }
                catch
                {
                }
            }
        }
        private void CheckDisposed()
        {
            if (_IsDisposed)
                throw new ObjectDisposedException(_Name, "NamedLock is Disposed");
        }
    }
}